home *** CD-ROM | disk | FTP | other *** search
- // Copyright 1994 by Jon Dart. All Rights Reserved.
-
- #include "notation.h"
- #include "board.h"
- #include "emove.h"
- #include "bearing.h"
- #include <ctype.h>
- #include <string.h>
-
- // This module handles I/O of standard algebraic notation (SAN).
- // Note that we can't put this into the Move class, because a
- // move doesn't contain enough info by itself to produce SAN -
- // we need the board position, too.
-
- void Notation::
- Image(const Board & b, const Move & m, char *image)
- {
- ExtendedMove emove(b, m);
- Piece p = emove.PieceMoved();
-
- if (emove.Special() == ExtendedMove::KCastle)
- {
- strcpy(image, "O-O");
- return;
- }
- else if (emove.Special() == ExtendedMove::QCastle)
- {
- strcpy(image, "O-O-O");
- return;
- }
- int k = 0;
-
- if (p.Type() == Piece::Pawn)
- {
- if (emove.Capture().IsEmpty())
- {
- image[k] = m.DestSquare().FileImage();
- k++;
- image[k] = m.DestSquare().RankImage();
- k++;
- }
- else
- {
- image[k] = m.StartSquare().FileImage();
- k++;
- image[k] = 'x';
- k++;
- image[k] = m.DestSquare().FileImage();
- k++;
- image[k] = m.DestSquare().RankImage();
- k++;
- }
- if (emove.Special() == ExtendedMove::Promotion)
- {
- image[k] = '=';
- k++;
- image[k] = Piece::Image(m.PromoteTo());
- k++;
- }
- image[k] = '\0';
- return;
- }
- else
- {
- image[k] = Piece::Image(p.Type());
- k++;
- Square squares[Bearing::MaxBearSq];
- unsigned n = Bearing::Attack(b, m.DestSquare(), b.Side(), squares);
- int dups = 0;
- int files[8];
- int ranks[8];
-
- if (n > 1)
- {
- for (unsigned i = 0; i < n; i++)
- {
- if (b[squares[i]].Type() == p.Type())
- {
- files[dups] = squares[i].File();
- ranks[dups] = squares[i].Rank(White);
- ++dups;
- }
- }
- }
- if (dups > 1)
- {
- // need to disambiguate move. There are some rare cases
- // (e.g. a player with 3 rooks) for which this code might
- // not be sufficient.
- if (files[0] != files[1])
- {
- image[k] = m.StartSquare().FileImage();
- k++;
- }
- else
- {
- image[k] = m.StartSquare().RankImage();
- k++;
- }
- }
- if (!emove.Capture().IsEmpty())
- {
- image[k] = 'x';
- k++;
- }
- image[k] = m.DestSquare().FileImage();
- k++;
- image[k] = m.DestSquare().RankImage();
- k++;
- image[k] = '\0';
- }
- }
-
- Move Notation::
- Value(const Board & board,
- const ColorType side, char *image)
- {
- char *p;
- int rank = 0;
- int file = 0;
-
- Piece::PieceType piece;
- Piece:: PieceType promotion = Piece::Invalid;
- Square dest, start;
- Boolean capture = False;
-
- for (p = image; isspace(*p); ++p);
- if (!isalpha(*p))
- return Move::NullMove();
- if (toupper(*p) == 'O')
- {
- // castling, we presume
- char tmp[10];
-
- strncpy(tmp, p, 9);
- for (char *q = tmp; *q; q++)
- *q = toupper(*q);
- return Move::Value(tmp, side);
- }
- if (isupper(*p))
- {
- piece = Piece::Value(*p);
- ++p;
- }
- else
- {
- piece = Piece::Pawn;
- file = *p - 'a' + 1;
- if (*(p + 1) == 'x')
- {
- capture = True;
- ++p;
- }
- }
- if (piece == Piece::Invalid)
- return Move::NullMove();
- if (piece != Piece::Pawn)
- {
- // look for disambiguating rank or file, e.g. 'b' in "Nbd7".
- if (isdigit(*p))
- {
- rank = *p - '0';
- ++p;
- }
- else if (*p != 'x' && isalpha(*p) && isalpha(*(p + 1)))
- {
- file = *p - 'a' + 1;
- ++p;
- }
- }
- if (*p == 'x')
- {
- capture = True;
- ++p;
- }
- // remainder of move should be a square identifier, e.g. "g7"
- dest = Square::Value(p);
- if (dest == Square::Invalid())
- return Move::NullMove();
- p += 2;
- if (*p == '=')
- {
- promotion = Piece::Value(*(p + 1));
- if (piece != Piece:: Pawn || promotion == Piece::Invalid)
- return Move::NullMove();
- }
- // ok, now we need to figure out where the start square is.
-
- int dups = 0;
-
- if (capture && piece == Piece::Pawn && board[dest].IsEmpty() &&
- dest.Rank(board.Side()) != 8)
- {
- // en passant capture, special case
- int start_rank = (board.Side() == White) ?
- dest.Rank(White) - 1 :
- dest.Rank(White) + 1;
-
- start = Square(file, start_rank, White);
- dups = 1;
- }
- else
- {
- static Square squares[36];
- int n = Bearing::Attack(board, dest, side, squares);
-
- for (int i = 0; i < n; i++)
- {
- Square maybe(squares[i]);
-
- if (board[maybe].Type() == piece)
- {
- if (file && maybe.File() != file)
- continue;
- else if (rank && maybe.Rank(White) != rank)
- continue;
- else
- {
- // Possible move to this square. Make sure it is legal.
-
- Board board_copy(board);
- ExtendedMove emove(board_copy,maybe,dest,promotion);
- board_copy.MakeMove(emove);
- if (board_copy.num_attacks(
- board_copy.KingPos(board_copy.OppositeSide()),
- board_copy.Side()) == 0)
- {
- ++dups;
- start = maybe;
- }
- }
- }
- }
- }
- if (dups == 1)
- return Move(start, dest, promotion);
- else // ambiguous move
- return Move::NullMove();
- }
-